#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define OWNADDR "0.0.0.0" // 我自己电脑的ip地址
#define OWNPORT 11111     // 我自己电脑的该程序的端口号

int main()
{
    printf("当前是服务器 IP:%s Port:%u\n", OWNADDR, OWNPORT);
    // 1、买手机（建立套接字）
    int socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (socketfd == -1)
    {
        printf("没钱了....,失败\n");
        return -1;
    }
    // 因为服务器立马退出之后，端口号不会及时释放
    // 此时如果服务器又马上运行，那么端口号会被占用，导致服务器分配端口号失败，连接失败
    // 所以设置端口号可以复用
    int optval = 1;
    setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

    // 2、绑定自己的电话号码（绑定自己的IP地址 和端口号）
    // 定义一个IPV4结构体变量，初始化自己的IP地址和端口号
    struct sockaddr_in ownAddr;
    ownAddr.sin_family = AF_INET;                 /*地址族  IPV4*/
    ownAddr.sin_port = htons(OWNPORT);            // htons 将本地端口号转为网络端口号
    ownAddr.sin_addr.s_addr = inet_addr(OWNADDR); // 将本地IP地址转为网络IP地址

    bind(socketfd, (struct sockaddr *)&ownAddr, sizeof(struct sockaddr_in));

    // 3、设置铃声(监听) listen
    listen(socketfd, 5);

    // 4、坐等电话（阻塞接收客户端的连接）
    printf("等待客户端连接.......\n");
    // 定义一个IPV4结构体变量，存储连接上来的客户端的IP地址 和 端口号
    struct sockaddr_in clientAddr;
    // 如果你要想要获取对方的IP地址和端口号，第三个参数必须把结构体的大小传递进去
    int len = sizeof(struct sockaddr_in);

    // 给 socketfd设置非阻塞属性
    int status = fcntl(socketfd, F_GETFL); // 得到这个套接字文件描述符的属性
    // 将得到的文件描述符的全部属性 中的 其中一个属性设置成 非阻塞
    status |= O_NONBLOCK;
    int ret = fcntl(socketfd, F_SETFL, status); // 把变量status的状态设置到文件描述符中
    if (ret == -1)
    {
        printf("fcntl error\n");
    }
    while (1)
    {
        // 此时是非阻塞，会一直不断地循环
        int newClientFd = accept(socketfd, (struct sockaddr *)&clientAddr, &len);
        if (newClientFd != -1)
        {
            // printf("有客户端连接上来了............\n");
            // 打印连接上来的客户端的IP地址和端口号，将网络字节序转为 本地字节序
            printf("连接上来的客户端IP:%s 端口号:%u\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
        }
        else
        {
            printf("没有客户端\n");
        }

        sleep(3);
    }

    // 5、关闭
    close(socketfd);

    return 0;
}